﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Globalization;
using System.Web;
using System.Reflection;
using System.Runtime.Serialization;
using System.IO;

namespace AppPressFramework
{
    // Abbreviated FormField Class to use in JS. FormField needs to be serialized fully in case of writing in CS file and for JS few fields needs to 
    // be serialized. Hence this class

    public enum TimeFormat
    {
        Hours = 1,
        Minutes = 2,
        Seconds = 3
    }
    [DataContract]
    internal class FormFieldJS
    {
        [DataMember]
        internal FormDefFieldType Type = 0;
        [DataMember]
        internal FormDefFieldStyle Style;
        [DataMember]
        internal long id;
        [DataMember]
        internal bool Static;

    }

    [DataContract]
    public class FormField
    {

        [DataMember]
        internal string fieldName;
        [DataMember]
        internal FormDefFieldType Type = 0;
        [DataMember]
        public FormDefFieldStyle Style;
        [DataMember]
        internal long id;
        [DataMember]
        public bool Static;
        [DataMember]
        public bool NonStatic = false;
        [DataMember]
        public bool Hidden = false;
        [DataMember]
        public FormField containerFormField; // fields within a formContainer
        [DataMember]
        internal FormDefFieldType OriginalType = 0;
        [DataMember]
        public bool DoNotSaveInDB;
        [DataMember]
        public bool Changeable = true;
        // for Type=FormContainer
        [DataMember]
        public int decimals = 0;
        [DataMember]
        public string width = null, height = null;
        [DataMember]
        internal List<ServerFunction> FieldFunctions = new List<ServerFunction>();
        [DataMember]
        internal string containerColumnName; // which grid column header the field will be displayed. For Sorting symbol
        [DataMember]
        public string Shortcut;
        [DataMember]
        public bool ZeroAsBlank;
        [DataMember]
        public int? MaxFileSizeInKB = null;
        [DataMember]
        public int? MaxChars;
        [DataMember]
        public string TableName; // table to save Pick Multiple Options        
        [DataMember]
        public string ForeignKey; // table to save Pick Multiple Options
        [DataMember]
        public string displayFieldName;
        [DataMember]
        internal int IsDateRange = 0; // 1 DateFrom, 2 DateTo
        [DataMember]
        public EncryptionType? EncryptionType;
        [DataMember]
        public bool Contiguous;
        [DataMember]
        public bool NonOverlapping;
        [DataMember]
        public bool Required = false;
        [DataMember]
        public bool EmailValidation = false;
        [DataMember]
        public string RegexValidation = null;
        [DataMember]
        public bool DateFromRequired;
        [DataMember]
        public bool DateToRequired;
        [DataMember]
        internal decimal? MinimumValue = null;
        [DataMember]
        public decimal? MaximumValue = null;
        [DataMember]
        public string CSSClass = null;
        [DataMember]
        public string LabelStyle = null;
        [DataMember]
        public string ControlStyle = null;
        [DataMember]
        public bool AllowMultiSelect = false;
        [DataMember]
        public bool StaticSubmitValue = false;
        [DataMember]
        public bool NoSubmit = false;
        [DataMember]
        public TimeFormat TimeFormat = TimeFormat.Minutes;
        [DataMember]
        public FileUploadStorageType FileUploadStorage = FileUploadStorageType.Database;
        [DataMember]
        public string FileUploadDirectory = null;
        [DataMember]
        public bool AutoUpload = false;
        [DataMember]
        public string Accept = null;
        [DataMember]
        public string GroupName = null;
        [DataMember]
        internal string ExtensionFormName;

        internal FormDef formDef;
        internal string Suffix = null;
        internal FormDef rowFormDef;
        internal List<FormField> rowFields = null;
        internal List<FormField> popupFields = null;
        internal Object fieldDetail = null; // Stores data specific to FieldType
        internal int NumberOfColumn = 1;
        internal string AutoClick;
        internal List<ServerFunctionParameter> Parameters = new List<ServerFunctionParameter>();
        internal UploadFileDetail UploadDetail;
        internal bool Extension = false;
        public long dbId = 0;
        public string DateFormat = null;
        internal List<Option> options = null; // for caching options generated from ForeignKey
        [DataMember]
        internal string FormNameProperty = null; // FormName for Redirect Field

        internal FormField()
        {
            this.id = AppPress.GetUniqueId();
        }
        /// <summary>
        /// ???
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="Type"></param>
        public FormField(string fieldName, FormDefFieldType Type)
            : this()
        {
            if (Type == FormDefFieldType.MergedForm)
                throw new Exception("FieldType: " + Type + " is not allowed for Field: " + fieldName);

            this.fieldName = fieldName;
            this.Type = Type;
        }
        internal FormField Clone()
        {
            return (FormField)MemberwiseClone();
        }
        internal FormField(string fieldName, FormDefFieldType formDefFieldType, FormDef parentFormDef)
            : this(fieldName, formDefFieldType)
        {
            this.formDef = parentFormDef;
        }
        internal FormField(string formName, string fieldName)
        {
            this.fieldName = fieldName;
            this.formDef = new FormDef();
            this.formDef.formName = formName;
        }
        internal MethodInfo GetMethod(AppPress a, string functionName)
        {
            var type = Util.GetType(a, formDef, id);
            //Add null check. Its come null for functionality in ExtensionForm.
            if (type != null)
                return Util.GetMethod(a, functionName, new Type[] { type });
            else
                return null;
        }

        internal List<ServerFunction> GetFieldFunctions(FunctionType functionType)
        {
            if (this.FieldFunctions == null)
                return new List<ServerFunction>();
            return this.FieldFunctions.FindAll(t => t.ServerFunctionType == functionType);
        }

        internal string GenerateSkin(AppPress a, bool forceStatic, string displayName = null)
        {
            var controlStyle = "AppPressControlStyle";
            var fieldStatic = forceStatic || Static;
            switch (Type)
            {
                case FormDefFieldType.MergedForm:
                case FormDefFieldType.UserControlScalar:
                    return "<!--|AppPress.FieldContent|-->";
                case FormDefFieldType.Pickone:
                    {

                        if (fieldStatic || a.skinType == SkinType.FO)
                            return "<span " + controlStyle + ">AppPressValue<span>";
                        var str = string.Empty;
                        if (Style == FormDefFieldStyle.DropDown)
                        {
                            str += @"<select id='AppPressId' onchange='AppPressOnChange' " + controlStyle + @">
                                    <!--|AppPress.PartBegin|--><option value='AppPressValue'>AppPressLabel</option><!--|AppPress.PartEnd|-->
                                    </select>";
                        }
                        else if (Style == FormDefFieldStyle.AutoComplete)
                        {
                            str += "<input type='text' id='AppPressId' value='AppPressValue' " + controlStyle + @"/>";
                        }
                        if (Style == FormDefFieldStyle.Radio)
                        {
                            str += @"<!--|AppPress.PartBegin|-->
                                    <div class='pickoneRadio'><input type='radio' id='AppPressId:AppPressValue' name='AppPressId'
                                    onclick='AppPressOnChange' Value='AppPressValue' " + controlStyle + @"/><label style='float: right;margin-left: 4px;margin-top: 1px;' for='AppPressId:AppPressValue'>AppPressLabel</label></div>
                                    <!--|AppPress.PartEnd|-->";
                        }
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.PickMultiple:
                    {
                        if (fieldStatic || a.skinType == SkinType.FO)
                            return "<!--|AppPress.PartBegin|--><span " + controlStyle + ">AppPressValue<span><!--|AppPress.PartEnd|-->";
                        var str = string.Empty; //Change width from 200px to 100%
                        var fieldClass = "";
                        if (CSSClass != null)
                            fieldClass = CSSClass;
                        var checkBoxesStr = @"<!--|AppPress.PartBegin|-->
                                                <label " + controlStyle + " class='" + fieldClass + @" pickMultipleCheckbox' for=""AppPressId:AppPressValue"" >
                                                    <input type=""checkbox"" id=""AppPressId:AppPressValue"" name=""AppPressId"" value=""AppPressValue"" >
                                                    AppPressLabel
                                                </label>
                                              <!--|AppPress.PartEnd|-->";

                        if (Style == FormDefFieldStyle.PopupCheckboxes)
                        {
                            str +=
                                @"<span id=""PickMultipleSelection_AppPressId""></span>&nbsp;
                                <input type='button' value='...' onclick=""$(JQueryEscape('#PickMultiplePoupup_AppPressId')).dialog({modal: true, title: 'Select Options', buttons: [ { text: 'Ok', click: function() { AppPress_UpdatePickMultipleOptions('AppPressId') } } ] })""/>
                                <div id=""PickMultiplePoupup_AppPressId"" style=""display:none"">" + checkBoxesStr + @"<br/><br/></div>";

                        }
                        else //if (Style == FormDefFieldStyle.InlineCheckboxes)
                        {
                            str += checkBoxesStr;
                        }

                        str += @"<span id=""AppPressErrorId""></span>";
                        return str;
                    }
                case FormDefFieldType.FileUpload:
                    {
                        if (a.skinType == SkinType.FO)
                            return "";
                        var s = "";
                        if (OriginalType != FormDefFieldType.MultiFileUpload)
                        {
                            s += @"<!--|AppPress.FileUpload.FileNamePartBegin|--><a class='appPressLink' href=""AppPressFileUploadDownloadUrl"">AppPressFileUploadFileName</a><!--|AppPress.FileUpload.FileNamePartEnd|-->
                                <!--|AppPress.FileUpload.DeletePartBegin|--><a title=""Delete File"" class='appPressButton' itemProp=""Delete"" onclick=""AppPressFileUploadDeleteUrl""><span></span></a><!--|AppPress.FileUpload.DeletePartEnd|-->";
                        }
                        s += @" <!--|AppPress.FileUpload.UploadPartBegin|-->
                                <a class='appPressButton fileinput-button' itemprop='Add'>
                                    <span></span>
                                    <input id='AppPressId' fileid='AppPressValue' type='file' name='file' title="""" />Choose File...
                                </a>
                                <span id='UIFileName:AppPressId' class='fileUploadPendingFileName'></span>
                                <div id='UIProgress:AppPressId'><div class='bar' style='width: 0%;'></div></div>
                                <a id='UIFileUpload:AppPressId' class='appPressButton appPressSmallButton' itemprop='None'><span></span></a>
                                <span id='AppPressErrorId'></span>
                                <!--|AppPress.FileUpload.UploadPartEnd|-->";
                        return s;
                    }
                case FormDefFieldType.FormContainerDynamic:
                    {
                        var fieldsSkin = "";
                        switch (GetFormContainerStyle())
                        {
                            case FormContainerStyle.Grid:
                                return GenerateGridSkin(a) + fieldsSkin;
                            case FormContainerStyle.InLine:
                                return @"<span id='AppPressFormErrorId'></span><!--|AppPress." + fieldName + @".RowBegin|--><!--|AppPress." + fieldName + @".RowEnd|-->" + fieldsSkin;
                            default:
                                throw new Exception("Invalid Form Container Style");
                        }
                    }
                case FormDefFieldType.Checkbox:
                    {
                        if ((fieldStatic && fieldName != "SelectRow") || a.skinType == SkinType.FO)
                            return "<span " + controlStyle + ">AppPressValue<span>";

                        string str = "<input type='checkbox' id='AppPressId' onclick='AppPressOnClick' AppPressValue /> " + displayName;
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.Password:
                    {
                        if (a.skinType == SkinType.FO)
                            return "";
                        var sizeAttr = MaxChars != null ? "maxlength='" + MaxChars + "'" : "";

                        string str = "<input " + controlStyle + @" type='password' " + sizeAttr + " id='AppPressId' value='AppPressValue'/>";
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.HTML:
                    return "<div id='AppPressId'>AppPressValue</div>";
                case FormDefFieldType.Number:
                case FormDefFieldType.Text:
                    {
                        if (fieldStatic || a.skinType == SkinType.FO)
                            return "<span " + controlStyle + @">AppPressValue</span>";
                        string str = "<input " + controlStyle + @" type='text' maxlength='AppPressMaxLength' id='AppPressId' value='AppPressValue' onchange='AppPressOnChange'/>";
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.TextArea:
                    {
                        if (fieldStatic || a.skinType == SkinType.FO)
                            return "<span " + controlStyle + @">AppPressValue</span>";
                        string str = "<textarea  " + controlStyle + @" maxlength='AppPressMaxLength' id='AppPressId' onchange='AppPressOnChange'>AppPressValue</textarea>";
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.Button:
                    {
                        if (a.skinType == SkinType.FO)
                            return "";

                        if (CSSClass.IsNullOrEmpty())
                            CSSClass = "";
                        var itemprop = fieldName;
                        if (this.OriginalType == FormDefFieldType.FormContainerGrid)
                        {
                            if (fieldName.StartsWith("Add")) itemprop = "Add";
                            if (fieldName.StartsWith("Modify")) itemprop = "Modify";
                            if (fieldName.StartsWith("Delete")) itemprop = "Delete";
                            if (fieldName.StartsWith("Save")) itemprop = "Save";
                        }
                        string str;
                        if (Style == FormDefFieldStyle.Link)
                        {
                            str = "<a id='AppPressId'  " + controlStyle + @" class='appPressLink " + CSSClass + "' onclick='AppPressOnClick'>" + displayName + "</a>";
                        }
                        else
                            str = "<a id='AppPressId'  " + controlStyle + @" class='appPressButton " + CSSClass + "' itemprop='" + itemprop + "' onclick='AppPressOnClick'><span></span>" + displayName + "</a>";
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }


                case FormDefFieldType.DateTime:
                    {
                        if (fieldStatic || a.skinType == SkinType.FO)
                            return "<span " + controlStyle + ">AppPressValue<span>";
                        string str = "<input type='text' " + controlStyle + @" size='10' maxlength='20' value='AppPressValue' id='AppPressId' onchange='AppPressOnChange' /> ";
                        str += "<span id='AppPressErrorId'></span>";
                        return str;
                    }
                case FormDefFieldType.ForeignKey:
                    return string.Empty;
            }
            throw new NotImplementedException();
        }

        internal string GenerateGridSkin(AppPress a)
        {
            string skin = "";

            var rowFormDef = GetContainerRowFormDef(a);

            if (rowFormDef == null)
            {
                skin += "<!--|AppPress." + fieldName + ".RowBegin|--><!--|AppPress." + fieldName + ".RowEnd|-->";
            }
            else
            {
                if (a.skinType == SkinType.FO)
                {
                    skin += "<fo:table>";
                }
                else
                {
                    var gridClass = "table ";
                    if (this.CSSClass != null)
                        gridClass += this.CSSClass;
                    if (height != null)
                        gridClass += " TableScroll ";
                    skin +=
                        "<table id='FormContainerTable' class='" + gridClass + " tbl_valign_top'";
                    if (width != null)
                    {
                        int w;
                        string wstr = width;
                        if (int.TryParse(width, out w))
                            wstr = w + "px";
                        skin += " style='width:" + wstr + "'";
                    }
                    skin += ">";


                    var cf = GenerateFormContainerFields(a);
                    if (formDef.FormType != FormType.ContainerRowFormGenerated || !cf.IsNullOrEmpty())
                    {
                        // column Heading already has the Caption
                        string heading = "";
                        if (this.width == null && formDef.FormType != FormType.ContainerRowForm && formDef.FormType != FormType.ContainerRowFormGenerated)
                            heading = "<span>" + GetDisplayName() + "</span>";
                        if (!heading.IsNullOrEmpty() || !cf.IsNullOrEmpty())
                        {
                            skin += "<caption class='tbl_heading'>" + heading + "<div class='AppPressFormContainerFields'>";
                            skin += cf;
                            skin += "</div></caption>";
                        }
                    }
                }

                var generateHeader = OriginalType != FormDefFieldType.MultiFileUpload;

                if (rowFormDef.Pivot)
                {
                    skin += "<tbody>";
                    foreach (var columnField in rowFormDef.formFields)
                    {
                        if (columnField.containerFormField != null || columnField.Type == FormDefFieldType.ForeignKey || columnField.Hidden)
                            continue;

                        if (columnField.Type == FormDefFieldType.MergedForm || columnField.Type == FormDefFieldType.UserControlScalar)
                        {
                            skin += @"<!--|AppPress." + this.fieldName + @".HeaderBegin|--><!--|AppPress." + columnField.fieldName + @".Begin|--><tr id='AppPressColumnId'><td AppPressLabelStyle>AppPressDisplayName</td><!--|AppPress." + this.fieldName + @".RowBegin|--><td><!--|AppPress." + columnField.fieldName + @".Begin|--><span id='AppPressContainerId' AppPressControlStyle><!--|AppPress.FieldContent|--></span><!--|AppPress." + columnField.fieldName + @".End|--></td><!--|AppPress." + this.fieldName + @".RowEnd|--></tr><!--|AppPress." + columnField.fieldName + @".End|--><!--|AppPress." + this.fieldName + @".HeaderEnd|-->";
                        }
                        else
                        {
                            skin += "<tr>";
                            skin += "<!--|AppPress." + this.fieldName + ".HeaderBegin|-->";
                            skin += "<td AppPressLabelStyle id='AppPressColumnId'><!--|AppPress." + columnField.fieldName + ".Begin|-->AppPressDisplayName<!--|AppPress." + columnField.fieldName + ".End|--></td>";
                            skin += "<!--|AppPress." + this.fieldName + ".HeaderEnd|-->";
                            skin += "<!--|AppPress." + this.fieldName + ".RowBegin|-->";
                            skin += "<td id='AppPressColumnId'><!--|AppPress." + columnField.fieldName + ".Begin|--><span id='AppPressContainerId' AppPressControlStyle>" + columnField.GenerateSkin(a, false) + "</span><!--|AppPress." + columnField.fieldName + ".End|--></td>";
                            skin += "<!--|AppPress." + this.fieldName + ".RowEnd|-->";
                            skin += "</tr>";
                        }

                    }
                    skin += "</tbody></table>";
                }
                else
                {
                    if (generateHeader)
                    {
                        skin += "<!--|AppPress." + this.fieldName + ".HeaderBegin|-->";
                        if (a.skinType == SkinType.FO)
                            skin += "<fo:table-header><fo:table-row>";
                        else
                            skin += "<thead><tr>";
                        foreach (var columnField in rowFormDef.formFields)
                        {
                            if (columnField.containerFormField != null || columnField.Type == FormDefFieldType.ForeignKey || columnField.Hidden)
                                continue;

                            skin += @"<!--|AppPress." + columnField.fieldName + @".Begin|-->";
                            if (a.skinType == SkinType.FO)
                                skin += "<fo:table-cell><fo:block font-size='8pt' font-family='sans-serif' font-weight='bold' space-after.optimum='20pt' text-align='start' padding =\"4pt\">" + columnField.GetDisplayName();
                            else
                            {
                                skin += "<th  id='AppPressColumnId' style='" + columnField.LabelStyle + "'>";
                                if (columnField.Type == FormDefFieldType.Checkbox)
                                    if (columnField.AllowMultiSelect && columnField.fieldName == "SelectRow")
                                    {
                                        skin += "<input type='checkbox' onclick='CheckUncheckAll(this,\"AppPressId\")'/>";
                                    }
                                if (columnField.Type != FormDefFieldType.Button)
                                    skin += @"AppPressDisplayName";

                            }
                            //// generate column fields
                            //foreach (var fField in formDef.formFields)
                            //{
                            //    if (fField.containerFormField == this && fField.containerColumnName == columnField.fieldName)
                            //    {
                            //        skin += GenerateSkin(a, false, fField.GetDisplayName());
                            //    }
                            //}
                            if (a.skinType == SkinType.FO)
                                skin += "</fo:block></fo:table-cell>";
                            else
                                skin += "</th>";

                            skin += @"<!--|AppPress." + columnField.fieldName + @".End|-->";
                        }
                        if (a.skinType == SkinType.FO)
                            skin += "</fo:table-row></fo:table-header>";
                        else
                            skin += "</tr></thead>";
                        skin += "<!--|AppPress." + this.fieldName + ".HeaderEnd|-->";
                    }
                    var columnSkin = string.Empty;
                    foreach (var columnField in rowFormDef.formFields)
                    {
                        if (columnField.containerFormField != null || columnField.Type == FormDefFieldType.ForeignKey || columnField.Hidden)
                            continue;
                        string displayName;
                        if (columnField.Changeable)
                        {
                            displayName = "AppPressDisplayName";
                        }
                        else
                        {
                            displayName = columnField.GetDisplayName();
                            //if (columnField.IsDateRange != 0)
                            //    displayName = displayName.Replace("From", "");
                        }
                        if (a.skinType == SkinType.FO)
                        {
                            columnSkin += "<fo:table-cell><fo:block font-size='8pt' font-family='sans-serif' space-after.optimum='20pt' text-align='start' padding =\"4pt\">";
                            columnSkin += "<!--|AppPress." + columnField.fieldName + ".Begin|-->";
                            columnSkin += columnField.GenerateSkin(a, false, columnField.GetDisplayName());
                            columnSkin += "<!--|AppPress." + columnField.fieldName + ".End|-->";
                            columnSkin += "</fo:block></fo:table-cell>";
                        }
                        else
                        {
                            columnSkin += "<!--|AppPress." + columnField.fieldName + ".Begin|-->";
                            columnSkin += "<td id='AppPressContainerId'";
                            if (columnField.Type == FormDefFieldType.Number)
                                columnSkin += @" style=""text-align:right""";
                            columnSkin += ">\n";
                            columnSkin += columnField.GenerateSkin(a, Static, displayName);
                            columnSkin += "</td><!--|AppPress." + columnField.fieldName + ".End|-->\n";
                        }
                    }

                    if (columnSkin.Trim() != string.Empty)
                    {
                        if (a.skinType == SkinType.FO)
                        {
                            skin += "<fo:table-body>";
                            skin += "<!--|AppPress." + fieldName + ".RowBegin|-->";
                            skin += "<fo:table-row>";
                        }
                        else
                        {
                            skin += "<tbody";
                            if (height != null)
                                skin += " style='height:" + height + "px' ";
                            skin += ">\n<!--|AppPress." + fieldName + ".RowBegin|-->";
                            skin += "<tr>";
                        }
                        skin += columnSkin;
                        if (a.skinType == SkinType.FO)
                        {
                            skin += "</fo:table-row>";
                            skin += "<!--|AppPress." + fieldName + ".RowEnd|-->";
                            skin += "</fo:table-body>";
                            skin += "</fo:table>";
                        }
                        else
                        {
                            skin += "</tr>";
                            skin += "<!--|AppPress." + fieldName + ".RowEnd|-->\n";
                            skin += "</tbody>";
                            skin += "</table>";
                        }
                    }

                }
            }
            return skin;
        }

        private string GetNativeWidth()
        {
            if (Type == FormDefFieldType.Checkbox && fieldName == "SelectRow")
                return "23px";
            if (Type == FormDefFieldType.DateTime && Style == FormDefFieldStyle.Time)
                return "150px";
            if (Type == FormDefFieldType.DateTime && Style != FormDefFieldStyle.Time)
                return "100px";
            if (Type == FormDefFieldType.Number)
                return (70 + decimals * 10) + "px";
            return null;
        }

        internal string GenerateFormContainerFields(AppPress a)
        {
            // generate fields attached to formContainer
            var skin = "";
            foreach (var fField in formDef.formFields)
            {
                if (fField.containerFormField == this/* && fField.containerColumnName == null*/)
                {
                    skin += "\n<!--|AppPress." + fField.fieldName + ".Begin|-->";
                    if (a.skinType != SkinType.FO)
                        skin += "<span id='AppPressContainerId'>";
                    string displayName;
                    if (fField.Changeable)
                    {
                        displayName = "AppPressDisplayName";
                    }
                    else
                    {
                        displayName = fField.GetDisplayName();
                    }
                    if (a.skinType != SkinType.FO)
                    {
                        if (fField.Type != FormDefFieldType.Button)
                        {
                            skin += "<span class='FieldTitle'>" + displayName + "</span>";
                        }
                    }
                    skin += fField.GenerateSkin(a, false, displayName);
                    if (a.skinType != SkinType.FO)
                        skin += "</span>";
                    skin += "<!--|AppPress." + fField.fieldName + ".End|-->\n";
                }
            }
            return skin;
        }


        internal string GetDisplayName(bool addRequired = true)
        {
            if (fieldName == "SelectRow")
                return "";
            string dName = displayFieldName != null ? displayFieldName : AppPress.InsertSpacesBetweenCaps(fieldName);
            if (addRequired)
                if (!Static && IsDateRange == 0)
                    if (Required) // add a trailing * if the field is required
                        dName += "*";

            return dName;
        }

        public string GetParameter(string parameterName)
        {
            return Parameters.Find(t => t.Name.Equals(parameterName, StringComparison.OrdinalIgnoreCase)).Value;
        }
        public string TryGetParameter(string parameterName)
        {
            if (Parameters == null)
                return null;
            var parameter = Parameters.Find(t => t.Name.Equals(parameterName, StringComparison.OrdinalIgnoreCase));
            if (parameter == null)
                return null;
            return parameter.Value;
        }

        internal string GetFieldValueFromDB(AppPress a, System.Data.IDataReader dr, int ford, FieldValue fieldValue)
        {
            switch (Type)
            {
                case FormDefFieldType.Text:
                case FormDefFieldType.HTML:
                case FormDefFieldType.TextArea:
                case FormDefFieldType.Password:
                case FormDefFieldType.Button:
                    if (dr.IsDBNull(ford))
                        return null;
                    var s = dr[ford].ToString();
                    if (this.EncryptionType.HasValue)
                    {
                        try
                        {
                            if (s == "N/A")
                                return s;
                            switch (this.EncryptionType.Value)
                            {
                                case AppPressFramework.EncryptionType.AES:
                                    {
                                        s = APCrypto.DecryptStringAES(s);
                                        break;
                                    }
                                case AppPressFramework.EncryptionType.DES:
                                    {
                                        s = Util.DecryptDES(s);
                                        break;
                                    }
                            }
                            if (this.Type == FormDefFieldType.Number)
                                decimal.Parse(s);
                        }
                        catch (Exception ex)
                        {
                            if (AppPress.Settings.developer)
                            {
                                if (this.Type == FormDefFieldType.Number)
                                    return "99999.99";
                                // ignore error and Generic string
                                var s1 = s;
                                s = "";
                                for (int i = 0; i < s1.Length; ++i)
                                    s += "*";
                                if (fieldValue != null)
                                    fieldValue.DoNotSaveInDB = true;// such fields should not be saved
                            }
                            else
                                throw;
                        }
                    }
                    return s;
                case FormDefFieldType.Number:
                    if (this.EncryptionType != null)
                        goto case FormDefFieldType.Text;
                    return dr.IsDBNull(ford) ? null :
                        (decimals == 0 ? dr[ford].ToString() : dr.GetDecimal(ford).ToString());
                case FormDefFieldType.Checkbox:
                    return dr.IsDBNull(ford) ? "0" : Convert.ToInt32(dr[ford]).ToString();
                case FormDefFieldType.Pickone:
                case FormDefFieldType.FileUpload:
                case FormDefFieldType.ForeignKey:
                    return dr.IsDBNull(ford) ? null : dr[ford].ToString();
                case FormDefFieldType.DateTime:
                    return dr.IsDBNull(ford) ? null : ((DateTime)dr.GetDateTime(ford)).ToString(DAOBasic.DBDateTimeFormat);

            }
            throw new Exception("GetFieldValueFromDB does not support Field Type:" + Type);
        }

        internal bool Sortable()
        {
            return !DoNotSaveInDB && Type != FormDefFieldType.Button;
        }

        public long? GetContainerRowForm(AppPress a)
        {
            var pServerFunction = a.serverFunction;
            var pFieldValue = a.fieldValue;
            try
            {
                foreach (var domainFunction in GetFieldFunctions(FunctionType.Domain))
                {
                    a.serverFunction = domainFunction;
                    var method = Util.GetMethod(a, domainFunction.FunctionName, new Type[] { typeof(AppPress), typeof(FormCallType) });
                    if (method == null)
                        return null;

                    a.fieldValue = new FieldValue();
                    a.fieldValue.formField = this;
                    var obj = Util.InvokeMethod(a, method, new object[] { a, FormCallType.GetContainerRowForm });
                    if (obj == null)
                        return null;
                    return (long?)Convert.ChangeType(obj, typeof(long));


                }
                return null;
            }
            finally
            {
                a.fieldValue = pFieldValue;
                a.serverFunction = pServerFunction;
            }
        }
        public FormDef GetContainerRowFormDef(AppPress a)
        {
            if (rowFormDef != null)
                return rowFormDef;
            var formDefId = GetContainerRowForm(a);
            if (formDefId == null)
            {
                if (OriginalType != 0)
                    return AppPress.FindFormDef(fieldName + "Row");
                return null;
            }
            return AppPress.FindFormDef((long)formDefId);
        }
        internal string GetContainerColumnName(AppPress a)
        {
            var pServerFunction = a.serverFunction;
            try
            {
                foreach (var domainFunction in GetFieldFunctions(FunctionType.Domain))
                {
                    a.serverFunction = domainFunction;
                    var method = Util.GetMethod(a, domainFunction.FunctionName, new Type[] { typeof(AppPress), typeof(FormCallType) });
                    if (method != null)
                        return (string)Util.InvokeMethod(a, method, new object[] { a, FormCallType.GetContainerColumnName });

                }
                return null;
            }
            finally
            {
                a.serverFunction = pServerFunction;
            }
        }

        internal static string RemoveBetweenMarkers(AppPress a, string skin, int skinStartIndex, string beginMarker, string endMarker, out int startIndex, out string betweenStr, string fileName)
        {
            if (a.skinType == SkinType.DOCX)
            {
                beginMarker = beginMarker.Replace("<", "&lt;").Replace(">", "&gt;");
                endMarker = endMarker.Replace("<", "&lt;").Replace(">", "&gt;");
            }
            startIndex = skin.IndexOf(beginMarker, skinStartIndex);
            if (startIndex == -1)
            {
                betweenStr = null;
                return skin;
            }
            int eCount = 1;
            var si = startIndex;
            // find nested endMarker
            // <Begin>
            //   <Begin>
            //   <End>
            //  <End>
            while (true)
            {
                var sIndex = skin.IndexOf(beginMarker, si + beginMarker.Length);
                var endIndex = skin.IndexOf(endMarker, si);
                if (endIndex == -1)
                    throw new AppPressException("Could not find:" + endMarker + " in Skin file: " + fileName);
                if (sIndex != -1 && sIndex < endIndex)
                {
                    eCount++;
                    si = sIndex;
                    continue;
                }
                eCount--;
                si = endIndex + endMarker.Length;
                if (eCount == 0)
                {
                    betweenStr = skin.Substring(startIndex, endIndex + endMarker.Length - startIndex);
                    return skin.Substring(0, startIndex) + skin.Substring(endIndex + endMarker.Length);
                }
            }
        }
        internal string RemoveBetweenMarkers(AppPress a, string skin, int skinStartIndex, string marker, out int startIndex, out string betweenStr, out bool outer, string formName)
        {

            outer = true;
            var beginMarker = @"<!--|AppPress." + fieldName + "." + marker + @"Begin|-->";
            var endMarker = @"<!--|AppPress." + fieldName + "." + marker + @"End|-->";
            var s = RemoveBetweenMarkers(a, skin, skinStartIndex, beginMarker, endMarker, out startIndex, out betweenStr, formDef.formName);

            if (betweenStr != null)
                return s;

            outer = false;
            beginMarker = @"<!--|" + formName + fieldName + marker + @"Begin|-->";
            endMarker = @"<!--|" + formName + fieldName + marker + @"End|-->";
            return RemoveBetweenMarkers(a, skin, skinStartIndex, beginMarker, endMarker, out startIndex, out betweenStr, formDef.formName);
        }
        internal string RemoveBetweenMarkers(AppPress a, string skin, int skinStartIndex, string marker, out int startIndex, out string betweenStr, out bool outer)
        {
            var formName = (marker == "Row" || marker == "Fields") ? "" : formDef.formName;
            return RemoveBetweenMarkers(a, skin, skinStartIndex, marker, out startIndex, out betweenStr, out outer, formName);
        }
        internal string RemoveBetweenMarkers(AppPress a, string ts, string marker, out bool outer, string replaceStr = null)
        {
            int startIndex;
            string betweenStr;
            while (true)
            {
                var s = RemoveBetweenMarkers(a, ts, 0, marker, out startIndex, out betweenStr, out outer);
                if (replaceStr != null && startIndex != -1)
                    s = s.Substring(0, startIndex) + replaceStr + s.Substring(startIndex);
                if (s.Length == ts.Length)
                    return ts;
                ts = s;

            }
        }


        internal static string ExtractBetweenMarkers(AppPress a, string skin, int skinStartIndex, string beginMarker, string endMarker, out string unique, out string betweenStr, string fileName)
        {
            if (a.skinType == SkinType.DOCX)
            {
                beginMarker = beginMarker.Replace("<", "&lt;").Replace(">", "&gt;");
                endMarker = endMarker.Replace("<", "&lt;").Replace(">", "&gt;");
            }
            int startIndex = skin.IndexOf(beginMarker, skinStartIndex);
            if (startIndex == -1)
            {
                unique = null;
                betweenStr = null;
                return skin;
            }
            int eCount = 1;
            var si = startIndex;
            // find nested endMarker
            // <Begin>
            //   <Begin>
            //   <End>
            //  <End>
            while (true)
            {
                var sIndex = skin.IndexOf(beginMarker, si + beginMarker.Length);
                var endIndex = skin.IndexOf(endMarker, si);
                if (endIndex == -1)
                    throw new AppPressException("Could not find:" + endMarker + " in Skin file: " + fileName);
                if (sIndex != -1 && sIndex < endIndex)
                {
                    eCount++;
                    si = sIndex;
                    continue;
                }
                eCount--;
                si = endIndex + endMarker.Length;
                if (eCount == 0)
                {
                    betweenStr = skin.Substring(startIndex + beginMarker.Length, endIndex - startIndex - beginMarker.Length);
                    unique = AppPress.GetUniqueId().ToString() + "jhsbhdbjhsdbjdbjhdbjbjd";
                    return skin.Substring(0, startIndex) + unique + skin.Substring(endIndex + endMarker.Length);
                }
            }
        }
        internal string ExtractBetweenMarkers(AppPress a, string skin, int skinStartIndex, string marker, out string unique, out string betweenStr, out bool outer, string formName, out string beginMarker, out string endMarker)
        {

            outer = true;
            beginMarker = @"<!--|AppPress." + fieldName + "." + marker + @"Begin|-->";
            endMarker = @"<!--|AppPress." + fieldName + "." + marker + @"End|-->";
            var s = ExtractBetweenMarkers(a, skin, skinStartIndex, beginMarker, endMarker, out unique, out betweenStr, formDef.formName);

            if (betweenStr != null)
                return s;

            outer = false;
            beginMarker = @"<!--|" + formName + fieldName + marker + @"Begin|-->";
            endMarker = @"<!--|" + formName + fieldName + marker + @"End|-->";
            return ExtractBetweenMarkers(a, skin, skinStartIndex, beginMarker, endMarker, out unique, out betweenStr, formDef.formName);
        }
        internal string ExtractBetweenMarkers(AppPress a, string skin, int skinStartIndex, string marker, out string unique, out string betweenStr, out bool outer, out string beginMarker, out string endMarker)
        {
            var formName = (marker == "Row" || marker == "Fields") ? "" : formDef.formName;
            return ExtractBetweenMarkers(a, skin, skinStartIndex, marker, out unique, out betweenStr, out outer, formName, out beginMarker, out endMarker);
        }
        internal FormContainerStyle GetFormContainerStyle()
        {
            if (OriginalType == FormDefFieldType.EmbeddedForm)
                return FormContainerStyle.InLine;
            if (OriginalType != FormDefFieldType.None || rowFormDef != null)
                return FormContainerStyle.Grid;
            if (FieldFunctions == null)
                return FormContainerStyle.InLine;
            var domainFunction = FieldFunctions.Find(t => t.ServerFunctionType == FunctionType.Domain);
            if (domainFunction == null)
                return FormContainerStyle.InLine;
            string style = domainFunction.TryGetFunctionParameterValue("Style");
            if (style == null)
                return FormContainerStyle.Grid;
            return (FormContainerStyle)int.Parse(style);

        }

        internal FieldValue NewFieldValue(FormDef containerFormDef)
        {

            var className = GetClassName(containerFormDef);
            var fieldValue1 = (FieldValue)Util.CreateInstance(className);
            if (fieldValue1 == null)
                switch (Type)
                {
                    case FormDefFieldType.FormContainerDynamic:
                        fieldValue1 = new FormContainerFieldValue();
                        break;
                    case FormDefFieldType.Pickone:
                    case FormDefFieldType.PickMultiple:
                        fieldValue1 = new PickFieldValue();
                        break;
                    case FormDefFieldType.DateTime:
                        fieldValue1 = new DateTimeFieldValue();
                        break;
                    case FormDefFieldType.FileUpload:
                        fieldValue1 = new FileUploadFieldValue();
                        break;
                    case FormDefFieldType.Number:
                        fieldValue1 = new NumberFieldValue();
                        break;
                    case FormDefFieldType.Button:
                        fieldValue1 = new ButtonFieldValue();
                        break;
                    default:
                        fieldValue1 = new FieldValue();
                        break;
                }
            fieldValue1.formField = this;
            fieldValue1.fieldDefId = id;
            return fieldValue1;
        }

        internal string GetClassName(FormDef f = null)
        {
            if (f == null || formDef.FormType == FormType.MergedForm || formDef.FormType == FormType.PluginForm)
                f = formDef;
            var calcClassName = f.formName + "Class+";
            //if (OriginalType == FormDefFieldType.UserControlScalar)
            //    calcClassName += AppPress.FindFormDef(ExtensionFormName).formFields[0].fieldName;
            //else
            calcClassName += fieldName;
            calcClassName += "FieldClass";
            while (f.ContainerFormField != null)
            {
                calcClassName = f.ContainerFormField.formDef.formName + "Class+" + calcClassName;
                f = f.ContainerFormField.formDef;
            }
            return calcClassName;
        }
        internal static string GetClassName(FormDef formDef, long fieldDefId)
        {
            var formField = formDef.GetFormField(fieldDefId);
            var calcClassName = formDef.formName + "Class+";
            //if (OriginalType == FormDefFieldType.UserControlScalar)
            //    calcClassName += AppPress.FindFormDef(ExtensionFormName).formFields[0].fieldName;
            //else
            calcClassName += formField.fieldName;
            calcClassName += "FieldClass";
            var f = formDef;
            while (f.ContainerFormField != null)
            {
                calcClassName = f.ContainerFormField.formDef.formName + "Class+" + calcClassName;
                f = f.ContainerFormField.formDef;
            }
            return calcClassName;
        }

        internal string GetDescription()
        {
            // for Error Display

            if (formDef.FormType == FormType.ContainerRowFormGenerated)
            {
                var fn = formDef.formName;
                if (fn.EndsWith("Row"))
                    fn = fn.Substring(0, fn.Length - 3);
                if (fn.EndsWith("Popup"))
                    fn = fn.Substring(0, fn.Length - 5);
                return "FormContainerGrid: " + fn + " Field: " + fieldName;
            }
            return "Form: " + formDef.formName + " Field: " + fieldName;
        }
    }
}
